package com.atguigu.gulimall.product.service.impl;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gulimall.product.biz.CategoryBizSerivce;
import com.atguigu.gulimall.product.entity.*;
import com.atguigu.gulimall.feign.search.SearchFeignClient;
import com.atguigu.gulimall.product.mapper.BaseTrademarkMapper;
import com.atguigu.gulimall.product.mapper.SkuInfoMapper;
import com.atguigu.gulimall.product.service.*;
import com.atguigu.gulimall.product.vo.SkuSaveInfoVo;
import com.atguigu.gulimall.search.entity.Goods;
import com.atguigu.gulimall.search.entity.SearchAttr;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author nicc
 * @description 针对表【sku_info(库存单元表)】的数据库操作Service实现
 * @createDate 2022-09-29 16:08:50
 */
@Service
@Slf4j
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo>
        implements SkuInfoService{

    @Autowired
    private SkuInfoMapper skuInfoMapper;

    @Autowired
    private SkuImageService skuImageService;

    @Autowired
    private SkuAttrValueService skuAttrValueService;

    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    private SpuSaleAttrValueService spuSaleAttrValueService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    //这个池子的队列是Integer.MAX；容易OOM
    ScheduledExecutorService pool = Executors.newScheduledThreadPool(4);

    @Autowired
    private RedissonClient redisson;

    @PostConstruct
    public void initBloomFilter(){
        RBloomFilter<Object> filter = redisson.getBloomFilter(RedisConst.BLOOM_SKUID);
        if(!filter.isExists()){
            log.info("布隆过滤器尚未初始化，正在初始化布隆过滤器...");
            //初始化分布式布隆
            filter.tryInit(1000000, 0.0000001);
            //拿到商品id
            List<Long> skuIds = getAllSkuId();

            skuIds.stream().forEach(item -> {
                filter.add(item);
            });
            log.info("布隆过滤器初始化完成...");

        }
    }


    @Override
    public Page<SkuInfo> getSkuListPage(Integer pageNum, Integer limit) {
        Page<SkuInfo> skuInfoPage = new Page<>(pageNum, limit);

        Page<SkuInfo> result = this.page(skuInfoPage);

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSkuInfo(SkuSaveInfoVo vo) {
        //1、保存sku_info
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(vo, skuInfo);
        skuInfoMapper.insert(skuInfo);

        Long skuId = skuInfo.getId();


        //2、保存sku_images
        List<SkuImage> images = vo.getSkuImageList().stream()
                .map(item -> {
                    SkuImage image = new SkuImage();
                    BeanUtils.copyProperties(item, image);
                    //回填sku_id
                    image.setSkuId(skuId);
                    return image;
                }).collect(Collectors.toList());
        skuImageService.saveBatch(images);

        //3、保存 sku平台属性名和值
        List<SkuAttrValue> attrValues = vo.getSkuAttrValueList().stream()
                .map(item -> {
                    SkuAttrValue skuAttrValue = new SkuAttrValue();
                    BeanUtils.copyProperties(item, skuAttrValue);
                    //回填sku_id
                    skuAttrValue.setSkuId(skuId);
                    return skuAttrValue;
                }).collect(Collectors.toList());
        skuAttrValueService.saveBatch(attrValues);


        //4、保存  sku销售属性名和值
        List<SkuSaleAttrValue> saleAttrValues = vo.getSkuSaleAttrValueList()
                .stream()
                .map(item -> {
                    SkuSaleAttrValue value = new SkuSaleAttrValue();
                    BeanUtils.copyProperties(item, value);
                    //回填sku_id、spu_id
                    value.setSkuId(skuId);
                    value.setSpuId(skuInfo.getSpuId());
                    value.setSaleAttrValueId(spuSaleAttrValueService.getId(skuInfo.getSpuId(), item.getSaleAttrValueName()));
                    return value;
                })
                .collect(Collectors.toList());
        skuSaleAttrValueService.saveBatch(saleAttrValues);

        //添加完商品之后，将商品id添加到布隆过滤器
        redisson.getBloomFilter(RedisConst.BLOOM_SKUID).add(skuId);

        log.info("sku信息保存成功： skuId={}",skuId);

        //把sku_price也添加一份到缓存中
        //redisTemplate.opsForValue().set(RedisConst.SKU_PRICE + skuId, skuInfo.getPrice().toString());

    }

    @Override
    public void changeOnSale(Long skuId, int flag) {
        //1、修改数据库状态
        skuInfoMapper.updateSaleStatus(skuId,flag);
        //TODO 2、上架的商品代表可以被检索到
    }

    @Override
    public BigDecimal getSkuPrice(Long skuId) {
        BigDecimal price =  skuInfoMapper.getSkuPrice(skuId);
        return price;
    }

    @Override
    public List<Long> getAllSkuId() {
        return skuInfoMapper.getAllSkuId();
    }

    @Override
    public void updateSkuInfo(SkuSaveInfoVo vo) {
        //1.修改数据库

        //2.延迟双删
        //2.1 第一次立即删除
        redisTemplate.delete(RedisConst.SKU_DETAIL_CACHE_PREFIX + vo.getId());

        //2.2 延迟10s删除
        //自己new Thread()有oom风险
        //        new Thread(()->{
        //            Thread.sleep(10000);
        //            redisTemplate.delete(RedisConst.SKU_DETAIL_CACHE_PREFIX+vo.getId());
        //        }).start();

        //提交延迟任务。有OOM风险
        pool.schedule(()->{
            redisTemplate.delete(RedisConst.SKU_DETAIL_CACHE_PREFIX + vo.getId());
        },10, TimeUnit.SECONDS);


        //立即结束
    }

    @Autowired
    private SearchFeignClient searchFeignClient;

    @Override
    public void onSale(Long skuId) {
        //1.修改状态
        this.changeOnSale(skuId, 1);

        //2.把sku信息添加到es中
        Goods goods = prepareGoods(skuId);

        //3.远程调用es服务进行保存
        searchFeignClient.onSaleGoods(goods);
    }

    @Override
    public void cancelSale(Long skuId) {
        //1.修改状态
        this.changeOnSale(skuId, 0);

        //2.远程调用es服务删除数据
        searchFeignClient.cancelSaleGoods(skuId);
    }

    @Autowired
    private BaseTrademarkMapper baseTrademarkMapper;

    @Autowired
    private CategoryBizSerivce categoryBizSerivce;

    @Autowired
    private ThreadPoolExecutor executor;

    /**
     * 生成某个具体商品在es中华进行存储的数据模型
     * @param skuId
     */
    private Goods prepareGoods(Long skuId) {
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);

        Goods goods = new Goods();

        //异步编排
        //1.查询商品sku基本信息
        CompletableFuture<Void> skuInfoFuture = CompletableFuture.runAsync(() -> {
            goods.setId(skuId);
            goods.setDefaultImg(skuInfo.getSkuDefaultImg());
            goods.setTitle(skuInfo.getSkuName());
            goods.setPrice(skuInfo.getPrice());
            goods.setCreateTime(new Date());
        }, executor);


        //2.查询品牌信息
        CompletableFuture<Void> trademarkFuture = CompletableFuture.runAsync(() -> {
            BaseTrademark trademark = baseTrademarkMapper.selectById(skuInfo.getTmId());
            goods.setTmId(trademark.getId());
            goods.setTmName(trademark.getTmName());
            goods.setTmLogoUrl(trademark.getLogoUrl());
        },executor);

        //3.查询商品三级分类信息
        CompletableFuture<Void> categoryFuture = CompletableFuture.runAsync(() -> {
            Long c3Id = skuInfo.getCategory3Id();
            CategoryViewEntity view = categoryBizSerivce.getCategoryView(c3Id);
            goods.setCategory1Id(view.getC1id());
            goods.setCategory1Name(view.getC1name());
            goods.setCategory2Id(view.getC2id());
            goods.setCategory2Name(view.getC2name());
            goods.setCategory3Id(view.getC3id());
            goods.setCategory3Name(view.getC3name());
        }, executor);



        //4.商品sku热度分
        goods.setHotScore(0L);


        //5.查询某个具体商品平台属性名和值
        CompletableFuture<Void> searchAttrFuture = CompletableFuture.runAsync(() -> {
            List<SearchAttr> searchAttrs = skuAttrValueService.getSkuAttrAndValue(skuId);
            goods.setAttrs(searchAttrs);
        }, executor);

        CompletableFuture.allOf(skuInfoFuture, trademarkFuture, categoryFuture, searchAttrFuture).join();

        return goods;
    }
}